package ru.compft.web.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import ru.compft.common.data.Module;
import ru.compft.common.data.ModulePage;
import ru.compft.common.services.ModuleService;
import ru.compft.common.utils.GlobalErrors;
import ru.compft.common.utils.GlobalConstants;
import ru.compft.web.adapter.ModuleAdapter;
import ru.compft.web.beans.ErrorBean;
import ru.compft.web.beans.ModuleBean;
import ru.compft.web.view.CurrentView;

import javax.annotation.Resource;
import java.io.Serializable;
import java.util.*;

/**
 * User: VVasiliev
 * Date: 14.06.12
 * Time: 13:43
 * Контроллер доступных модулей системы
 * Основной контроллер системы.
 */
@Controller("modulesController")
@RequestMapping("/modules")
@Scope("session")
public class ModulesController implements Serializable {
    private static final long serialVersionUID = 3183713069283644633L;

    private static final Logger logger = LoggerFactory.getLogger(ModulesController.class);

    //    private static final String CURRENT_VIEW = "currentView";
    private static final String ALL_MODULES = "allModules";
    private static final String PAGE_LIST = "pageList";

    private static final String MODULE = "module";
    private static final String TAB = "tab";

    public ModulesController() {
        System.out.println("--------------ModulesController constructor -------------------- ");
    }

    @Resource(name = "moduleService")
    private ModuleService moduleService;

    @Resource(name = "currentView")
    private CurrentView currentView;

    @Resource(name = "moduleBean")
    private ModuleBean moduleBean;

    private Map<String, Module> allModulesMap; // меп модулей по коду
    private Map<String, List<ModulePage>> pagesToModuleMap;  // меп страниц модуля по коду модуля
    private Map<String, ModulePage> pagesMap; // меп страниц модуля по их коду

    public Map<String, Module> getAllModulesMap() {
        return allModulesMap;
    }

    public void setAllModulesMap(Map<String, Module> allModulesMap) {
        this.allModulesMap = allModulesMap;
    }

    public Map<String, List<ModulePage>> getPagesToModuleMap() {
        if (pagesToModuleMap == null) setPagesToModuleMap(new HashMap<String, List<ModulePage>>());
        return pagesToModuleMap;
    }

    public void setPagesToModuleMap(Map<String, List<ModulePage>> pagesToModuleMap) {
        this.pagesToModuleMap = pagesToModuleMap;
    }

    public Map<String, ModulePage> getPagesMap() {
        if (pagesMap == null) setPagesMap(new HashMap<String, ModulePage>());
        return pagesMap;
    }

    public void setPagesMap(Map<String, ModulePage> pagesMap) {
        this.pagesMap = pagesMap;
    }

    public ModuleBean getModuleBean() {
        return moduleBean;
    }

    public void setModuleBean(ModuleBean moduleBean) {
        this.moduleBean = moduleBean;
    }

//    todo оставить для примера
//    @RequestMapping(method = RequestMethod.POST)
//    public String add(@Valid AppointmentForm appointment, BindingResult result) {
//        if (result.hasErrors()) {
//            return "appointments/new";
//        }
//        appointmentBook.addAppointment(appointment);
//        return "redirect:/appointments";
//    }

    /**
     * Инициализация
     * Список всех доступных модулей для приложения
     *
     * @return
     */
    @ModelAttribute(ALL_MODULES)
    private List<Module> init() {
        System.out.println("Initialisation modules");
        final List<Module> allModules = moduleService.getAllModules();

        final Map<String, Module> result = new HashMap<String, Module>();
        // возвращаем только те модули, у которых стоит признак visible
        if (!CollectionUtils.isEmpty(allModules)) {
            for (Module module : allModules) {
                if (module.isVisible()) {
                    final String moduleCode = module.getCode();
                    result.put(moduleCode, module);

                    // далее меппируем страницы этого модуля
                    final List<ModulePage> pageList = module.getPageList();
                    if (!CollectionUtils.isEmpty(pageList)) {
                        final List<ModulePage> resultPages = new ArrayList<ModulePage>();

                        // возвращаем только те страницы, у которых стоит признак visible
                        for (ModulePage modulePage : pageList) {
                            if (modulePage.isVisible()) {
                                // добавим в результирующий список
                                resultPages.add(modulePage);
                                // добавим в меп страниц модулей
                                getPagesMap().put(modulePage.getCode(), modulePage);
                            }
                        }
                        getPagesToModuleMap().put(moduleCode, resultPages);
                    }
                }
            }
        }
        // запишем в память модули
        setAllModulesMap(result);

        // Сортируем оставшиеся модули по полю order
        ArrayList<Module> moduleArrayList = new ArrayList<Module>(result.values());
        Collections.sort(moduleArrayList);

        // отдадим отсортированную коллекцию
        return moduleArrayList;
    }

    @ModelAttribute(CurrentView.BEAN_NAME)
    public CurrentView getCurrentView() {
        return currentView;
    }

    /**
     * Отображение по умолчанию. Если не найдется ни одного подходящего handler запроса
     *
     * @return
     */
    @RequestMapping(value = "/index*", method = RequestMethod.GET)
    public String showDefault() {
        System.out.println("Show view.");
        return GlobalConstants.DEFAULT_MODULES_VIEW;
    }

    /**
     * Навигация по списку модулей.
     * Проверка корректности введенного параметра
     *
     * @param moduleCode //     * @param view
     * @param result
     * @return
     */
    @RequestMapping(value = "/index*", method = RequestMethod.GET, params = {MODULE})
    public String showModule(@RequestParam(value = MODULE, required = false) String moduleCode,
                             @ModelAttribute(ErrorBean.BEAN_NAME) ErrorBean errorBean,
                             BindingResult result,
                             Model model) {
        System.out.println("Try find module with code = " + moduleCode);
        if (StringUtils.hasText(moduleCode)) {
            if (getAllModulesMap().containsKey(moduleCode)) {
                final Module module = getAllModulesMap().get(moduleCode);

                // преобразуем в бин
                ModuleAdapter.copyToModuleBean(module, moduleBean);
                setModuleBean(moduleBean);

                currentView.setModule(moduleCode);

                // добавляем атрибут в модель
                model.addAttribute(PAGE_LIST, getPagesToModuleMap().get(moduleCode));

                return GlobalConstants.MODULES + GlobalConstants.SLASH + moduleCode;
            } else {
                result.rejectValue(ErrorBean.FIELD_NAME, GlobalErrors.MODULE_NOT_FOUND, new String[]{moduleCode}, null);
            }
        }

        return showDefault();
    }

    /**
     * Навигация по страницам модуля.
     * Проверка корректности введенных параметров - модуля и таба
     *
     * @param moduleCode
     * @param tab        //     * @param view
     * @param result
     * @return
     */
    @RequestMapping(value = "/index*", method = RequestMethod.GET, params = {MODULE, TAB})
    public String showPage(@RequestParam(value = MODULE, required = false) String moduleCode,
                           @RequestParam(value = TAB, required = false) String tab,
                           @ModelAttribute(ErrorBean.BEAN_NAME) ErrorBean errorBean,
                           BindingResult result,
                           Model model) {
        // сначала проверяем и загружаем модуль по коду
        showModule(moduleCode, errorBean, result, model);

        // если не было ошибкок на предыдущем шаге, проверяем корректность таба
        if (!result.hasErrors()) {
            System.out.println("Try find module page with code = " + tab);

            if (StringUtils.hasText(tab)) {
                if (getPagesMap().containsKey(tab)) {
                    currentView.setTab(tab);

//                    return GlobalConstants.REDIRECT + GlobalConstants.SLASH + tab;
                    final String url = GlobalConstants.FORWARD + GlobalConstants.SLASH + GlobalConstants.MODULES + GlobalConstants.SLASH +
                            moduleCode + GlobalConstants.SLASH + tab + GlobalConstants.DO_SUFFIX;

                    System.out.println("Return url = " + url);
                    return url;
                } else {
                    result.rejectValue(ErrorBean.FIELD_NAME, GlobalErrors.MODULE_PAGE_NOT_FOUND, new String[]{tab}, null);
                }
            }
        }

        return showDefault();
    }


//    public String getModuleById() {
//        final ServletRequest servletRequest = (ServletRequest) FacesUtils.getExternalContext().getRequest();
//        final String moduleBeanId = servletRequest.getParameter("moduleBeanId");
//
//        final ModuleBean moduleBean = (ModuleBean) FacesUtils.getBackingBean(WebConst.MODULE_BEAN);
//
//        if (moduleBean != null && StringUtils.hasText(moduleBeanId)) {
//            Long id = 0L;
//            try {
//                id = Long.valueOf(moduleBeanId);
//            } catch (NumberFormatException e) {
//                logger.error("Module bean Id = " + moduleBeanId, e);
//            }
//            final ModuleService modulesService = (ModuleService) FacesUtils.getSpringBean(WebConst.MODULE_SERVICE);
//            final Module module = modulesService.getModuleById(id);
//            if (module != null) {
//                ModuleAdapter.copyToModuleBean(module, moduleBean);
//                return GlobalConstants.SUCCESS;
//            }
//        }
//        return GlobalConstants.FAILURE;
//    }

    public String cancel() {
        return GlobalConstants.SUCCESS;
    }

//    public void editModule() {
//        final ModuleBean moduleBean = (ModuleBean) FacesUtils.getBackingBean(WebConst.MODULE_BEAN);
//
//        // получаем сервис работы с модулями
//        if (moduleBean != null) {
//            if (moduleBean.getId() == null) {
//                // такого быть здесь не должно. Выходим из метода
//                // todo сделать через файл messages
//                FacesUtils.addErrorMessage(null, "Ошибка при редактировании модуля");
//                return;
//            }
//            // валидация
//            if (!ModuleValidator.isValid(moduleBean)) {
//                // todo сделать через файл messages
//                FacesUtils.addErrorMessage(null, "Ошибка валидации модуля");
//                return;
//            }
//
//            final Module module = ModuleAdapter.convertToModule(moduleBean);
//            if (module == null) {
//                // todo сделать через файл messages
//                FacesUtils.addErrorMessage(null, "Ошибка конвертации модуля");
//                return;
//            }
//
//            final ModuleService modulesService = (ModuleService) FacesUtils.getSpringBean(WebConst.MODULE_SERVICE);
//            Module editable = modulesService.editModule(module);
//
//            if (editable != null) {
//                // сохранено успешно
//                // todo сделать через файл messages
//                FacesUtils.addInfoMessage(null, "Модуль изменен успешно");
//            } else {
//                // сохранено не успешно
//                // todo сделать через файл messages
//                FacesUtils.addErrorMessage(null, "Ошибка изменения модуля");
//            }
//        }
//    }
}
